<script setup lang="ts">
import type { BlockState } from '~/types'
import { isDev, toggleDev } from '~/composables'

const WIDTH: number = 10
const HEIGHT: number = 10
const state = ref<BlockState[][]>([])

function generateMines(state: BlockState[][], inital: BlockState) {
  for (const row of state) {
    for (const block of row) {
      if (Math.abs(inital.x - block.x) < 1)
        continue
      if (Math.abs(inital.y - block.y) < 1)
        continue
      block.mine = Math.random() < 0.1
    }
  }
  updateNumbers(state)
}

const directions = [
  [-1, -1],
  [-1, 0],
  [-1, 1],
  [0, -1],
  [0, 1],
  [1, -1],
  [1, 0],
  [1, 1],
]

function updateNumbers(state: BlockState[][]) {
  state.forEach((row) => {
    row.forEach((block) => {
      if (block.mine)
        return
      getSiblings(block).forEach((s) => {
        if (s.mine)
          block.adjacentMines++
      })
    })
  })
}

function getSiblings(block: BlockState) {
  return directions.map(([dx, dy]) => {
    const x2: number = block.x + dx
    const y2: number = block.y + dy
    if (x2 < 0 || x2 >= WIDTH || y2 < 0 || y2 >= HEIGHT) {
      return undefined
    }
    return state.value[y2][x2]
    // if (state[y2][x2].mine)
    //   block.adjacentMines += 1
  }).filter(Boolean) as BlockState[]
}

let mineGenerated = false
function onClick(block: BlockState) {
  if (!mineGenerated) {
    generateMines(state.value, block)
    mineGenerated = true
  }
  if (block.flagged)
    return
  block.revealed = true
  if (block.mine) {
    alert('Game Over')
  }
  if (block.flagged)
    return
  expendZero(block)
}

function onRightClick(block: BlockState) {
  if (block.revealed)
    return
  block.flagged = !block.flagged
}

function expendZero(block: BlockState) {
  if (block.adjacentMines)
    return
  getSiblings(block).forEach((s) => {
    if (!s.revealed && !s.flagged) {
      s.revealed = true
      expendZero(s)
    }
  })
}

watchEffect(checkGameState)

function checkGameState() {
  if (!mineGenerated)
    return
  const blocks = state.value.flat()

  if (blocks.every(block => block.revealed || block.flagged)) {
    if (blocks.every(block => block.mine && block.flagged))
      alert('You chat')

    else
      alert('You Win')
  }
}

function reset() {
  state.value = Array.from({ length: HEIGHT }, (_, y) =>
    Array.from({ length: WIDTH }, (_, x): BlockState => ({
      x,
      y,
      adjacentMines: 0,
      revealed: false,
    })))
}
reset()
</script>

<template>
  <div>
    Minesweeper
    <button @click="toggleDev()">
      {{ isDev }}
    </button>
    <div p5>
      <div
        v-for="row, y in state" :key="y"
        flex="~" items-center justify-center
      >
        <MineBlock
          v-for="block, x in row" :key="x"
          :block="block"
          @click="onClick(block)"
          @contextmenu.prevent="onRightClick(block)"
        />
        <!-- <button

          border="2 gray-400/10"
          :class="getBlockClass(block)"
          flex="~ gap-1"
          m="0.5" h-10 w-10
          items-center
          justify-center
          vertical-top
          hover:bg-gray

        >
          <template v-if="block.flagged">
            <div i-mdi:flag text-red-500 />
          </template>
          <template v-else-if="block.revealed || dev">
            <div v-if="block.mine" i-mdi:mine />
            <div v-else>
              {{ block.mine ? "x" : block.adjacentMines }}
            </div>
          </template>
        </button> -->
      </div>
    </div>
  </div>
</template>
